package com.haha.onebot.start;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.haha.onebot.config.GlobalConfig;
import com.haha.onebot.entity.Bot;
import com.haha.onebot.exception.MyRunTimeException;
import jakarta.annotation.Resource;
import lombok.extern.log4j.Log4j2;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.core.annotation.Order;
import org.springframework.scheduling.concurrent.CustomizableThreadFactory;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.client.WebSocketClient;
import org.springframework.web.socket.client.WebSocketConnectionManager;
import org.springframework.web.socket.client.standard.StandardWebSocketClient;

import java.io.IOException;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;


/**
 * 启动机器人消息监听器
 */
@SpringBootApplication
@Log4j2
@Order(1)
public class BotChannel implements CommandLineRunner {

    @Value("${bot.ws_url}")
    private String wsUrl;

    @Resource
    private BotSocketHandler botSocketHandler;

    @Resource
    private RestTemplate restTemplate;

    @Resource
    private ObjectMapper  objectMapper;

    @Resource
    private Bot bot;

    private WebSocketConnectionManager manager;

    private WebSocketSession session;

    @Override
    public void run(String... args) throws Exception {
        log.info("===============");
        log.info("机器人启动");
        initSocketConnection();
        initBot();
    }

    public void initBot() {
        String data = restTemplate.postForObject(bot.getBaseUrl() + "/get_login_info", null, String.class);
        if (data == null) {
            log.error("获取机器人信息失败");
            throw new MyRunTimeException("获取机器人信息失败");
        }
        try {
            JsonNode jsonNode = objectMapper.readTree(data);
            JsonNode data1 = jsonNode.get("data");
            String userId = data1.get("user_id").asText();
            bot.setBotId(userId);
            log.info("机器人信息：{}", bot);
        } catch (IOException e) {
            log.error("解析机器人信息失败", e);
            throw new MyRunTimeException("解析机器人信息失败");
        }
    }

    /**
     * 初始化websocket连接
     */
    public void initSocketConnection() {
        ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor(new CustomizableThreadFactory("WebSocket-Reconnect-"));

        executor.execute(() -> {
            Integer reconnectCount = 0;
            while (reconnectCount < bot.getReconnectMax() && !GlobalConfig.shutDown.get()) {
                reconnectCount++;
                WebSocketClient client = new StandardWebSocketClient();
                try {
                    CompletableFuture<WebSocketSession> future = new CompletableFuture<>();
                    client.doHandshake(botSocketHandler, wsUrl).addCallback(
                            session -> {
                                log.info("WebSocket连接成功");
                                future.complete(session);
                            },
                            ex -> {
                                log.error("WebSocket连接失败", ex);
                                future.completeExceptionally(ex);
                            }
                    );
                    this.session = future.get();
                    break;
                } catch (Exception e) {
                    log.error("连接失败，等待{}秒后重连", bot.getReconnectInterval() / 1000, e);
                    Thread.currentThread().interrupt();
                    try {
                        TimeUnit.MILLISECONDS.sleep(bot.getReconnectInterval());
                    } catch (InterruptedException ex) {
                        log.error("线程被中断", ex);
                        Thread.currentThread().interrupt();
                        throw new MyRunTimeException(ex.getMessage());
                    }
                }
            }
        });
    }

    /**
     * 断开重连
     */
    public void reconnection() {
        if (this.session != null && this.session.isOpen()) {
            try {
                this.session.close();
            } catch (IOException e) {
                log.error("关闭旧的WebSocket会话时出错", e);
            }
        }
        initSocketConnection();
    }

}
